home *** CD-ROM | disk | FTP | other *** search
/ Nebula 1 / Nebula One.iso / Educational / RasMol / Source / infile.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-10-10  |  44.3 KB  |  1,682 lines

  1. /* infile.c
  2.  * RasMol2 Molecular Graphics
  3.  * Roger Sayle, August 1995
  4.  * Version 2.6
  5.  */
  6. #include "rasmol.h"
  7.  
  8. #ifdef IBMPC
  9. #include <windows.h>
  10. #include <malloc.h>
  11. #endif
  12. #ifdef APPLEMAC
  13. #include <Types.h>
  14. #endif
  15. #ifndef sun386
  16. #include <stdlib.h>
  17. #endif
  18.  
  19. #include <string.h>
  20. #include <ctype.h>
  21. #include <stdio.h>
  22. #include <math.h>
  23.  
  24. #define INFILE
  25. #include "infile.h"
  26. #include "molecule.h"
  27. #include "abstree.h"
  28. #include "command.h"
  29. #include "transfor.h"
  30.  
  31. #ifndef APPLEMAC
  32. #ifndef IBMPC
  33. #include <sys/types.h>
  34. #include <sys/time.h>
  35. #endif
  36. #include <time.h>
  37. #endif
  38.  
  39.  
  40. #ifdef MMIO
  41. #include "mmio.h"
  42. #endif
  43.  
  44. #define GroupPool    8
  45.  
  46. #define FeatHelix    1
  47. #define FeatSheet    2
  48. #define FeatTurn     3
  49.  
  50.  
  51. typedef struct {
  52.     int init, term;
  53.     char chain;
  54.     char type;
  55.     } FeatEntry;
  56.  
  57. #define FeatSize    32
  58. typedef struct _Feature {
  59.     struct _Feature __far *fnext;
  60.         FeatEntry data[FeatSize];
  61.         int count;
  62.     } Feature;
  63.  
  64.  
  65. typedef struct {
  66.       char src[4];
  67.       char dst[4];
  68.       } ConvTable;
  69.  
  70. #define MAXALCATOM   5
  71. static ConvTable AlcAtomTable[MAXALCATOM] = {
  72.     { { 'S', 'O', '2', ' ' }, { ' ', 'S', '2', ' ' } },  /*  1 */
  73.     { { 'C', 'A', 'R', ' ' }, { ' ', 'C', ' ', ' ' } },  /*  2 */
  74.     { { 'N', 'A', 'R', ' ' }, { ' ', 'N', ' ', ' ' } },  /*  3 */
  75.     { { 'N', 'A', 'M', ' ' }, { ' ', 'N', ' ', ' ' } },  /*  4 */
  76.     { { 'N', 'P', 'L', '3' }, { ' ', 'N', '3', ' ' } },  /*  5 */
  77.                  };
  78.  
  79. static char PDBInsert;
  80. static Feature __far *FeatList;
  81. static char Record[202];
  82. static FILE *DataFile;
  83.  
  84. /* Macros for commonly used loops */
  85. #define ForEachAtom  for(chain=Database->clist;chain;chain=chain->cnext) \
  86.              for(group=chain->glist;group;group=group->gnext)    \
  87.              for(aptr=group->alist;aptr;aptr=aptr->anext)
  88. #define ForEachBond  for(bptr=Database->blist;bptr;bptr=bptr->bnext)
  89.  
  90.  
  91. /* Forward Reference */
  92. void DestroyDatabase();
  93.  
  94.  
  95. #ifdef APPLEMAC
  96. /* External RasMac Function Declaration! */
  97. void SetFileInfo( char*, OSType, OSType, short );
  98. #endif
  99.  
  100.  
  101. static void FatalInFileError(ptr)
  102.     char *ptr;
  103. {
  104.     char buffer[80];
  105.  
  106.     sprintf(buffer,"InFile Error: %s!",ptr);
  107.     RasMolFatalExit(buffer);
  108. }
  109.  
  110.  
  111. /*================================*/
  112. /* File/String Handling Functions */
  113. /*================================*/
  114.  
  115. static int FetchRecord()
  116. {
  117.     register char *ptr;
  118.     register int ch;
  119.  
  120.     if( feof(DataFile) )
  121.     {   *Record = '\0';
  122.         return( False );
  123.     }
  124.  
  125.     ptr = Record;
  126.     do {
  127.         ch = getc(DataFile);
  128.         if( ch == '\n' )
  129.         {   *ptr = 0;
  130.             return( True );
  131.         } else if( ch == '\r' )
  132.         {   ch = getc(DataFile);
  133.             if( ch != '\n' )
  134.                 ungetc(ch,DataFile);
  135.             *ptr = 0;
  136.             return( True );
  137.         } else if( ch == EOF )
  138.         {   *ptr = 0;
  139.             return( ptr != Record+1 );
  140.         } else *ptr++ = ch;
  141.     } while( ptr < Record+200 );
  142.  
  143.     /* skip to the end of the line! */
  144.     do { ch = getc(DataFile);
  145.     } while( (ch!='\n') && (ch!='\r') && (ch!=EOF) );
  146.  
  147.     if( ch == '\r' )
  148.     {   ch = getc(DataFile);
  149.         if( ch != '\n' )
  150.             ungetc(ch,DataFile);
  151.     }
  152.     *ptr = 0;
  153.     return( True );
  154. }
  155.  
  156.  
  157. static void ExtractString( len, src, dst )
  158.     int len;  char *src, *dst;
  159. {
  160.     register char *ptr;
  161.     register char ch;
  162.     register int i;
  163.  
  164.     ptr = dst;
  165.     for( i=0; i<len; i++ )
  166.     {   if( *src )
  167.     {   ch = *src++;
  168.             *dst++ = ch;
  169.             if( ch != ' ' ) 
  170.         ptr = dst;
  171.     } else break;
  172.     }
  173.     *ptr = 0;
  174. }
  175.  
  176.  
  177. static Long ReadValue( pos, len )
  178.     int pos, len;
  179. {
  180.     register Long result;
  181.     register char *ptr;
  182.     register char ch;
  183.     register int neg;
  184.  
  185.     result = 0;
  186.     neg = False;
  187.     ptr = Record+pos;
  188.     while( len-- )
  189.     {   ch = *ptr++;
  190.     if( (ch>='0') && (ch<='9') )
  191.     {   result = (10*result)+(ch-'0');
  192.     } else if( ch=='-' )
  193.         neg = True;
  194.     }
  195.     return( neg? -result : result );
  196. }
  197.  
  198.  
  199. /*===================================*/
  200. /* File Format Independent Functions */
  201. /*===================================*/
  202.  
  203. #ifdef FUNCPROTO
  204. static void UpdateFeature( FeatEntry __far*, int );
  205. #endif
  206.  
  207. static FeatEntry __far *AllocFeature()
  208. {
  209.     register Feature __far *ptr;
  210.  
  211.     if( !FeatList || (FeatList->count==FeatSize) )
  212.     {   ptr = (Feature __far*)_fmalloc(sizeof(Feature));
  213.         if( !ptr ) FatalInFileError("Memory allocation failed");
  214.         /* Features are always deallocated! */
  215.  
  216.         ptr->fnext = FeatList;
  217.         ptr->count = 0;
  218.         FeatList = ptr;
  219.     } else ptr = FeatList;
  220.  
  221.     return( &(ptr->data[ptr->count++]) );
  222. }
  223.  
  224.  
  225. static void UpdateFeature( ptr, mask )
  226.     FeatEntry __far *ptr;  int mask;
  227. {
  228.     register Chain __far *chain;
  229.     register Group __far *group;
  230.  
  231.     for( chain=Database->clist; chain; chain=chain->cnext )
  232.         if( chain->ident == ptr->chain )
  233.         {   group=chain->glist;
  234.             while( group && (group->serno<ptr->init) )
  235.                 group = group->gnext;
  236.  
  237.             while( group && (group->serno<=ptr->term) )
  238.             {   group->struc |= mask;
  239.                 group = group->gnext;
  240.             }
  241.  
  242.             if( NMRModel )
  243.             {  continue;
  244.             } else return;
  245.         }
  246. }
  247.  
  248.  
  249. static void ProcessFeatures()
  250. {
  251.     register Feature __far *next;
  252.     register Feature __far *ptr;
  253.     register int i;
  254.  
  255.     InfoTurnCount = 0;
  256.     InfoHelixCount = 0;
  257.     InfoLadderCount = 0;
  258.     InfoStrucSrc = SourcePDB;
  259.  
  260.     for( ptr=FeatList; ptr; ptr=next )
  261.     {    if( Database )
  262.              for( i=0; i<ptr->count; i++ )
  263.                  if( ptr->data[i].type==FeatHelix )
  264.                  {   UpdateFeature( &ptr->data[i], HelixFlag );
  265.                      InfoHelixCount++;
  266.                  } else if( ptr->data[i].type==FeatSheet )
  267.                  {   UpdateFeature( &ptr->data[i], SheetFlag );
  268.                      InfoLadderCount++;
  269.                  } else /* FeatTurn */
  270.                  {   UpdateFeature( &ptr->data[i], TurnFlag );
  271.                      InfoTurnCount++;
  272.                  }
  273.  
  274.          /* Deallocate Memory */
  275.          next = ptr->fnext;
  276.          _ffree( ptr );
  277.     }
  278. }
  279.  
  280.  
  281.  
  282.  
  283. /*==============================*/
  284. /* Molecule File Format Parsing */
  285. /*==============================*/
  286.  
  287. static Long ReadPDBCoord( offset )
  288.     int offset;
  289. {
  290.     register int len,neg;
  291.     register Long result;
  292.     register char *ptr;
  293.     register char ch;
  294.  
  295.     result = 0;
  296.     neg = False;
  297.     len = 8;
  298.  
  299.     ptr = Record+offset;
  300.     while( len-- )
  301.     {   ch = *ptr++;
  302.         if( (ch>='0') && (ch<='9') )
  303.         {   result = (10*result)+(ch-'0');
  304.         } else if( ch=='-' )
  305.             neg = True;
  306.     }
  307.  
  308.     /* Handle Chem3D PDB Files! */
  309.     if( Record[offset+3]=='.' )
  310.         result /= 10;
  311.     return( neg? -result : result );
  312. }
  313.  
  314.  
  315. static void ProcessPDBGroup( heta, serno )
  316.     int heta, serno;
  317. {
  318.     PDBInsert = Record[26];
  319.     if( !CurChain || (CurChain->ident!=Record[21]) )
  320.         CreateChain( Record[21] );
  321.     CreateGroup( GroupPool );
  322.  
  323.     CurGroup->refno = FindResNo( Record+17 );
  324.     CurGroup->serno = serno;
  325.     ProcessGroup( heta );
  326. }
  327.  
  328.  
  329. static void ProcessPDBAtom( heta )
  330.     int heta;
  331. {
  332.     register Bond __far *bptr;
  333.     register Atom __far *ptr;
  334.     register Long dx,dy,dz;
  335.     register int temp,serno;
  336.  
  337.     dx = ReadPDBCoord(30);
  338.     dy = ReadPDBCoord(38);
  339.     dz = ReadPDBCoord(46);
  340.  
  341.     /* Process Pseudo Atoms Limits!! */
  342.     if( (Record[13]=='Q') && (Record[12]==' ') )
  343.     {   temp = (int)ReadValue(60,6);
  344.         if( MMinMaxFlag )
  345.         {   if( temp < MinMainTemp )
  346.             {   MinMainTemp = temp;
  347.             } else if( temp > MaxMainTemp )
  348.                 MaxMainTemp = temp;
  349.         }
  350.  
  351.         /* Dummy co-ordinates! */
  352.         if( (dx==dy) && (dx==dz) )
  353.         {   if( !dx || (dx == 9999000L) )
  354.                 return;
  355.         }
  356.  
  357.         if( HMinMaxFlag || MMinMaxFlag )
  358.         {   if( dx < MinX )
  359.             {   MinX = dx;
  360.             } else if( dx > MaxX )
  361.                 MaxX = dx;
  362.  
  363.             if( dy < MinY )
  364.             {   MinY = dy;
  365.             } else if( dy > MaxY )
  366.                 MaxY = dy;
  367.  
  368.             if( dz < MinZ )
  369.             {   MinZ = dz;
  370.             } else if( dz > MaxZ )
  371.                 MaxZ = dz;
  372.         }
  373.         return;
  374.     }
  375.  
  376.  
  377.     /* Ignore XPLOR Pseudo Atoms!! */
  378.     if( (dx==9999000L) && (dy==9999000L) && (dz==9999000L) )
  379.         return;
  380.  
  381.     serno = (int)ReadValue(22,4);
  382.     if( !CurGroup || (CurGroup->serno!=serno)
  383.         || (CurChain->ident!=Record[21])
  384.         || (PDBInsert!=Record[26]) )
  385.         ProcessPDBGroup( heta, serno );
  386.  
  387.  
  388.     ptr = CreateAtom();
  389.     ptr->refno = ComplexAtomType(Record+12);
  390.     ptr->serno = (int)ReadValue(6,5);
  391.     ptr->temp = (int)ReadValue(60,6);
  392.     ptr->altl = Record[16];
  393.  
  394.     ptr->xorg =  dx/4;
  395.     ptr->yorg =  dy/4;
  396.     ptr->zorg = -dz/4;
  397.  
  398.     if( heta ) ptr->flag |= HeteroFlag;
  399.     ProcessAtom( ptr );
  400.  
  401.     /* Create biopolymer Backbone */
  402.     if( IsAlphaCarbon(ptr->refno) && IsProtein(CurGroup->refno) )
  403.     {   if( ConnectAtom )
  404.         {   dx = ConnectAtom->xorg - ptr->xorg;
  405.             dy = ConnectAtom->yorg - ptr->yorg;
  406.             dz = ConnectAtom->zorg - ptr->zorg;
  407.  
  408.             /* Break backbone if CA-CA > 7.00A */
  409.             if( dx*dx+dy*dy+dz*dz < (Long)1750*1750 )
  410.             {   bptr = ProcessBond(ptr,ConnectAtom,NormBondFlag);
  411.                 bptr->bnext = CurChain->blist;
  412.                 CurChain->blist = bptr;
  413.             } else ptr->flag |= BreakFlag;
  414.         }
  415.         ConnectAtom = ptr;
  416.     } else if( IsSugarPhosphate(ptr->refno) && IsNucleo(CurGroup->refno) )
  417.     {   if( ConnectAtom )
  418.         {   bptr = ProcessBond(ConnectAtom,ptr,NormBondFlag);
  419.             bptr->bnext = CurChain->blist;
  420.             CurChain->blist = bptr;
  421.         }
  422.         ConnectAtom = ptr;
  423.     }
  424. }
  425.  
  426.  
  427. static void ProcessPDBColourMask()
  428. {
  429.     register MaskDesc *ptr;
  430.     register char *mask;
  431.     register int i;
  432.  
  433.     if( MaskCount==MAXMASK )
  434.         FatalInFileError("Too many COLOR records in file");
  435.     ptr = &UserMask[MaskCount];
  436.     mask = ptr->mask;
  437.  
  438.  
  439.     ptr->flags = 0;
  440.     for( i=6; i<11; i++ )
  441.         if( (*mask++ = Record[i]) != '#' )
  442.             ptr->flags |= SerNoFlag;
  443.  
  444.     for( i=12; i<20; i++ )
  445.         *mask++ = Record[i];
  446.     *mask++ = Record[21];
  447.  
  448.     for( i=22; i<26; i++ )
  449.         if( (*mask++ = Record[i]) != '#' )
  450.             ptr->flags |= ResNoFlag;
  451.     *mask++ = Record[26];
  452.  
  453.     ptr->r = (int)(ReadPDBCoord(30)>>2) + 5;
  454.     ptr->g = (int)(ReadPDBCoord(38)>>2) + 5;
  455.     ptr->b = (int)(ReadPDBCoord(46)>>2) + 5;
  456.     ptr->radius = (short)(5*ReadValue(54,6))>>1;
  457.     MaskCount++;
  458. }
  459.  
  460.  
  461. int LoadPDBMolecule( fp, flag )
  462.     FILE *fp;  int flag;
  463. {
  464.     register FeatEntry __far *ptr;
  465.     register int srcatm, dstatm;
  466.     register char *src, *dst;
  467.     register int i,ignore;
  468.  
  469.     ignore = False;
  470.     FeatList = (void __far*)0;
  471.     DataFile = fp;
  472.     NMRModel = 0;
  473.  
  474.     while( FetchRecord() )
  475.     {   if( *Record == 'A' )
  476.         {   if( !ignore && !strncmp("ATOM",Record,4) )
  477.                 ProcessPDBAtom( False );
  478.  
  479.         } else switch(*Record)
  480.         {   case('C'):    if( !strncmp("CONE",Record,4) )
  481.                           {   if( ignore || flag ) continue;
  482.  
  483.                               srcatm = (int)ReadValue(6,5);
  484.                               if( srcatm )
  485.                                   for( i=11; i<=36 && Record[i]; i+=5 )
  486.                                   {   dstatm = (int)ReadValue(i,5);
  487.                                       if( dstatm && (dstatm>srcatm) )
  488.                                           CreateBondOrder(srcatm,dstatm);
  489.                                   }
  490.                                
  491.                           } else if( !strncmp("COMP",Record,4) )
  492.                           {   if( Record[9]==' ' )  /* First COMPND record */
  493.                                   ExtractString(60,Record+10,InfoMoleculeName);
  494.  
  495.                           } else if( !strncmp("CRYS",Record,4) )
  496.                           {   dst = InfoSpaceGroup;  src=Record+55;
  497.                               while( *src && src<Record+66 )
  498.                                   if( *src!=' ' ) 
  499.                                   {   *dst++ = *src++;
  500.                                   } else src++;
  501.                               *dst = 0;
  502.  
  503.                               InfoCellA = ReadValue( 6,9)/1000.0;
  504.                               InfoCellB = ReadValue(15,9)/1000.0;
  505.                               InfoCellC = ReadValue(24,9)/1000.0;
  506.  
  507.                               InfoCellAlpha = Deg2Rad*(ReadValue(33,7)/100.0);
  508.                               InfoCellBeta =  Deg2Rad*(ReadValue(40,7)/100.0);
  509.                               InfoCellGamma = Deg2Rad*(ReadValue(47,7)/100.0);
  510.  
  511.                           } else if( !strncmp("COLO",Record,4) )
  512.                               ProcessPDBColourMask();
  513.                           break;
  514.  
  515.             case('E'):    if( !strncmp("ENDM",Record,4) )
  516.                           {   /* break after single model??? */
  517.                               if( flag )
  518.                               {   ConnectAtom = (void __far*)0;
  519.                                   CurGroup = (void __far*)0;
  520.                                   CurChain = (void __far*)0;
  521.                               } else ignore = True;
  522.  
  523.                           } else if( !strncmp("END",Record,3) )
  524.                               if( !Record[4] || (Record[4]==' ') )
  525.                               {   /* Treat END same as TER! */
  526.                                   ConnectAtom = (void __far*)0;
  527.                                   CurGroup = (void __far*)0;
  528.                                   CurChain = (void __far*)0;
  529.                               }
  530.                           break;
  531.  
  532.             case('H'):    if( !strncmp("HETA",Record,4) )
  533.                           {   if( !ignore ) ProcessPDBAtom(True);
  534.                           } else if( !strncmp("HELI",Record,4) )
  535.                           {   if( ignore ) continue;
  536.  
  537.                               /* Remaining HELIX record fields   */
  538.                               /* 38-39 .... Helix Classification */
  539.                               /* 31 ....... Same Chain as 19?    */
  540.                               ptr = AllocFeature();
  541.                               ptr->type = FeatHelix;
  542.                               ptr->chain = Record[19];
  543.                               ptr->init = (int)ReadValue(21,4);
  544.                               ptr->term = (int)ReadValue(33,4);
  545.                               
  546.                           } else if( !strncmp("HEAD",Record,4) )
  547.                           {   ExtractString(40,Record+10,InfoClassification);
  548.                               ExtractString( 4,Record+62,InfoIdentCode);
  549.                           }
  550.                           break;
  551.  
  552.             case('M'):    if( !strncmp("MODE",Record,4) )
  553.                               if( flag ) NMRModel++;
  554.                           break;
  555.  
  556.             case('S'):    if( !strncmp("SHEE",Record,4) )
  557.                           {   if( ignore ) break;
  558.                               /* Remaining SHEET record fields   */
  559.                               /* 38-39 .... Strand Parallelism   */
  560.                               /* 32 ....... Same Chain as 21?    */
  561.                               ptr = AllocFeature();
  562.                               ptr->type = FeatSheet;
  563.                               ptr->chain = Record[21];
  564.                               ptr->init = (int)ReadValue(22,4);
  565.                               ptr->term = (int)ReadValue(33,4);
  566.                           }
  567.                           break;
  568.  
  569.             case('T'):    if( !strncmp("TURN",Record,4) )
  570.                           {   if( ignore ) continue;
  571.  
  572.                               ptr = AllocFeature();
  573.                               ptr->type = FeatTurn;
  574.                               ptr->chain = Record[19];
  575.                               ptr->init = (int)ReadValue(20,4);
  576.                               ptr->term = (int)ReadValue(31,4);
  577.                           } else if( !strncmp("TER",Record,3) )
  578.                           {   if( !Record[3] || (Record[3]==' ') )
  579.                               {   ConnectAtom = (void __far*)0;
  580.                                   CurGroup = (void __far*)0;
  581.                                   CurChain = (void __far*)0;
  582.                               }
  583.                           }
  584.                           break;
  585.         }
  586.     }
  587.  
  588.     if( Database )
  589.         strcpy(InfoFileName,DataFileName);
  590.     if( FeatList ) ProcessFeatures();
  591.     return( True );
  592. }
  593.  
  594.  
  595. int LoadMDLMolecule( fp )
  596.     FILE *fp;
  597. {
  598.     register Bond __far *bptr;
  599.     register Atom __far *src;
  600.     register Atom __far *dst;
  601.     register Atom __far *ptr;
  602.  
  603.     register int i,type;
  604.     register int atoms, bonds;
  605.     register int srcatm,dstatm;
  606.     register Long dx, dy, dz;
  607.     register Card dist2;
  608.     register Real scale;
  609.     register char *cptr;
  610.  
  611.     DataFile = fp;
  612.  
  613.     FetchRecord(); /* Molecule Name */
  614.     ExtractString(78,Record,InfoMoleculeName);
  615.  
  616.     FetchRecord(); /* Program Details */
  617.     FetchRecord(); /* Comments */
  618.  
  619.     FetchRecord();
  620.     atoms = (int)ReadValue(0,3);
  621.     bonds = (int)ReadValue(3,3);
  622.  
  623.     if( !atoms )
  624.         return( False );
  625.  
  626.     CreateMolGroup();
  627.     for( i=1; i<=atoms; i++ )
  628.     {   FetchRecord();
  629.         ptr = CreateAtom();
  630.  
  631.         cptr = Record+31;
  632.         while( *cptr == ' ' ) cptr++;
  633.         ptr->refno = SimpleAtomType(cptr);
  634.  
  635.         switch( (int)ReadValue(36,3) )
  636.         {   case(1):  ptr->temp =  300;  break;
  637.             case(2):  ptr->temp =  200;  break;
  638.             case(3):  ptr->temp =  100;  break;
  639.             case(5):  ptr->temp = -100;  break;
  640.             case(6):  ptr->temp = -200;  break;
  641.             case(7):  ptr->temp = -300;  break;
  642.             default:  ptr->temp = 0;
  643.         }
  644.         ptr->serno = i;
  645.  
  646.         ptr->xorg =  ReadValue( 0,10)/40;
  647.         ptr->yorg =  ReadValue(10,10)/40;
  648.         ptr->zorg = -ReadValue(20,10)/40;
  649.         ProcessAtom( ptr );
  650.     }
  651.  
  652.     for( i=0; i<bonds; i++ )
  653.     {   FetchRecord();
  654.         srcatm = (int)ReadValue(0,3);
  655.         dstatm = (int)ReadValue(3,3);
  656.         type =   (int)ReadValue(6,3);
  657.  
  658.         if( type==2 )                 /* DOUBLE */
  659.         {   CreateBond(srcatm,dstatm,DoubBondFlag);
  660.         } else if( type==3 )          /* TRIPLE */
  661.         {   CreateBond(srcatm,dstatm,TripBondFlag);
  662.         } else if( type==4 )          /* AROMATIC */
  663.         {   CreateBond(srcatm,dstatm,AromBondFlag);
  664.         } else                        /* SINGLE */
  665.             CreateBond(srcatm,dstatm,NormBondFlag);
  666.     }
  667.  
  668.     for( bptr=Database->blist; bptr; bptr=bptr->bnext )
  669.         if( bptr->flag & NormBondFlag )
  670.         {   src = bptr->srcatom;
  671.             dst = bptr->dstatom;
  672.             if( (src->refno==2) && (dst->refno==2) )
  673.             {   dx = dst->xorg - src->xorg;
  674.                 dy = dst->yorg - src->yorg;
  675.                 dz = dst->zorg - src->zorg;
  676.                 if( dx || dy || dz )
  677.                 {   dist2 = dx*dx + dy*dy + dz*dz;
  678.                     scale = 385.0/sqrt(dist2);
  679.                     break;
  680.                 }
  681.             }
  682.         }
  683.  
  684.     if( bptr )
  685.     {   for( ptr=CurGroup->alist; ptr; ptr=ptr->anext )
  686.         {   ptr->xorg = (Long)(ptr->xorg*scale);
  687.             ptr->yorg = (Long)(ptr->yorg*scale);
  688.             ptr->zorg = (Long)(ptr->zorg*scale);
  689.         }
  690.         MinX = (Long)(MinX*scale);  MaxX = (Long)(MaxX*scale);
  691.         MinY = (Long)(MinY*scale);  MaxY = (Long)(MaxY*scale);
  692.         MinZ = (Long)(MinZ*scale);  MaxZ = (Long)(MaxZ*scale);
  693.     }
  694.     return( True );
  695. }
  696.  
  697.  
  698. int LoadXYZMolecule( fp )
  699.     FILE *fp;
  700. {
  701.     auto char type[12];
  702.     auto double xpos, ypos, zpos;
  703.     auto double charge, u, v, w;
  704.     auto int atoms;
  705.  
  706.     register Atom __far *ptr;
  707.     register char *src,*dst;
  708.     register int i,count;
  709.  
  710.  
  711.     DataFile = fp;
  712.     /* Number of Atoms */
  713.     FetchRecord();
  714.     sscanf(Record,"%d",&atoms);
  715.  
  716.     /* Molecule (step) Description */
  717.     FetchRecord();
  718.     src = Record;
  719.     while( *src == ' ' )
  720.         src++;
  721.  
  722.     dst = InfoMoleculeName;
  723.     for( i=0; i<78; i++ )
  724.         if( *src ) *dst++ = *src++;
  725.     *dst = '\0';
  726.  
  727.     if( atoms )
  728.     {   CreateMolGroup();
  729.         for( i=0; i<atoms; i++ )
  730.         {   FetchRecord();
  731.             ptr = CreateAtom();
  732.             ptr->serno = i;
  733.  
  734.             xpos = ypos = zpos = 0.0;
  735.             count = sscanf(Record,"%s %lf %lf %lf %lf %lf %lf %lf",
  736.                            type, &xpos, &ypos, &zpos, &charge, &u, &v, &w );
  737.  
  738.             ptr->refno = SimpleAtomType(type);
  739.             ptr->xorg =  (Long)(250.0*xpos);
  740.             ptr->yorg =  (Long)(250.0*ypos);
  741.             ptr->zorg = -(Long)(250.0*zpos);
  742.  
  743.             if( (count==5) || (count==8) )
  744.             {   ptr->temp = (short)(100.0*charge);
  745.             } else ptr->temp = 0;
  746.             ProcessAtom( ptr );
  747.         }
  748.     }
  749.     return( True );
  750. }
  751.  
  752.  
  753. static int FindSybylRefNo( ptr )
  754.     char *ptr;
  755. {
  756.     register char *src,*dst;
  757.     auto char name[4];
  758.  
  759.     src = ptr;
  760.     dst = name;
  761.     if( ptr[1] && (ptr[1]!='.') )
  762.     {   *dst++ = ToUpper(*src);  src++;
  763.         *dst++ = ToUpper(*src);  src++;
  764.     } else
  765.     {   *dst++ = ' ';
  766.         *dst++ = ToUpper(*src);
  767.         src++;
  768.     }
  769.  
  770.     if( *src )
  771.     {   src++;
  772.  
  773.         if( *src == 'a' )
  774.         {   *dst++ = ' ';
  775.             *dst = ' ';
  776.         } else if( *src == 'p' )
  777.         {   *dst++ = '3';
  778.             *dst = ' ';
  779.         } else
  780.         {   *dst++ = *src++;
  781.             if( *src && (*src!='+') )
  782.             {   *dst = *src;
  783.             } else *dst = ' ';
  784.         }
  785.     } else
  786.     {   *dst++ = ' ';
  787.         *dst = ' ';
  788.     }
  789.     return( NewAtomType(name) );
  790. }
  791.  
  792.  
  793. int LoadMol2Molecule( fp )
  794.     FILE *fp;
  795. {
  796.     double xpos, ypos, zpos;
  797.     int features, sets, serno;
  798.     int atoms, bonds, structs;
  799.     int srcatm, dstatm;
  800.  
  801.     char name[8];
  802.     char type[8];
  803.  
  804.     register Atom __far *ptr;
  805.     register char *src, *dst;
  806.     register int i;
  807.  
  808.  
  809.     DataFile = fp;
  810.     while( FetchRecord() )
  811.     {   if( !*Record || *Record=='#' )
  812.             continue;
  813.  
  814.         if( !strncmp("@<TRIPOS>MOLECULE",Record,17) ||
  815.             !strncmp("@MOLECULE",Record,9) )
  816.         {   FetchRecord();  /* Molecule Name */
  817.             src = Record;
  818.             while( *src==' ' )
  819.                 src++;
  820.  
  821.             dst = InfoMoleculeName;
  822.             while( (*dst++ = *src++) );
  823.  
  824.             FetchRecord();
  825.             atoms = bonds = structs = features = sets = 0;
  826.             sscanf(Record,"%d %d %d %d %d", &atoms, &bonds, &structs,
  827.                                             &features, &sets );
  828.  
  829.             FetchRecord();  /* Molecule Type  */
  830.             FetchRecord();  /* Charge Type    */
  831.  
  832.         } else if( !strncmp("@<TRIPOS>ATOM",Record,13) ||
  833.                    !strncmp("@ATOM",Record,5) )
  834.         {   if( !atoms ) continue;
  835.  
  836.             CreateMolGroup();
  837.             for( i=0; i<atoms; i++ )
  838.             {    FetchRecord();
  839.                  ptr = CreateAtom();
  840.  
  841.                  sscanf(Record,"%d %s %lf %lf %lf %s", &serno, name,
  842.                                 &xpos, &ypos, &zpos, type );
  843.  
  844.                  ptr->refno = FindSybylRefNo( type );
  845.                  ptr->serno = serno;
  846.                  /* ptr->serno = i; */
  847.  
  848.                  ptr->xorg =  (Long)(250.0*xpos);
  849.                  ptr->yorg =  (Long)(250.0*ypos);
  850.                  ptr->zorg = -(Long)(250.0*zpos);
  851.                  ProcessAtom( ptr );
  852.             }
  853.  
  854.         } else if( !strncmp("@<TRIPOS>BOND",Record,13) ||
  855.                    !strncmp("@BOND",Record,5) )
  856.             for( i=0; i<bonds; i++ )
  857.             {   FetchRecord();
  858.                 sscanf(Record,"%d %d %d %s",&serno,&srcatm,&dstatm,type);
  859.                 if( !strncmp(type,"ar",2) )
  860.                 {   CreateBond(srcatm,dstatm,AromBondFlag);
  861.                 } else if( *type == '2' )
  862.                 {   CreateBond(srcatm,dstatm,DoubBondFlag);
  863.                 } else /* *type == '1' */
  864.                     CreateBond(srcatm,dstatm,NormBondFlag);
  865.             }
  866.     }
  867.     return( True );
  868. }
  869.  
  870.  
  871. static int FindAlchemyRefNo()
  872. {
  873.     register char *ptr;
  874.     register int i;
  875.     char name[4];
  876.  
  877.     ptr = Record+6;
  878.     if( !isalpha(ptr[1]) )
  879.     {   name[0] = ' ';
  880.         for( i=0; i<3; i++ )
  881.             name[i+1] = ToUpper(ptr[i]);
  882.         ptr = name;
  883.     } else
  884.     {   for( i=0; i<4; i++ )
  885.             ptr[i] = ToUpper(ptr[i]);
  886.  
  887.         for( i=0; i<MAXALCATOM; i++ )
  888.             if( !strncmp(AlcAtomTable[i].src,ptr,4) )
  889.             {   ptr = AlcAtomTable[i].dst;
  890.                 break;
  891.             }
  892.     }
  893.     return( NewAtomType(ptr) );
  894. }
  895.  
  896.  
  897. int LoadAlchemyMolecule( fp )
  898.     FILE *fp;
  899. {
  900.     auto int serno,srcatm,dstatm;
  901.     register Atom __far *ptr;
  902.     register int atoms, bonds;
  903.     register char *chptr;
  904.     register int i;
  905.  
  906.     DataFile = fp;
  907.     FetchRecord();
  908.     atoms = (int)ReadValue(0,5);
  909.     bonds = (int)ReadValue(13,5);
  910.     ExtractString(38,Record+41,InfoMoleculeName);
  911.  
  912.     if( !atoms )
  913.         return( False );
  914.  
  915.     CreateMolGroup();
  916.     for( i=0; i<atoms; i++ )
  917.     {   FetchRecord();
  918.         ptr = CreateAtom();
  919.  
  920.         ptr->refno = FindAlchemyRefNo();
  921.         ptr->temp = (int)ReadValue(40,8);
  922.         ptr->serno = (int)ReadValue(0,5);
  923.         /* ptr->serno = i+1; */
  924.  
  925.         ptr->xorg =  ReadValue(12,7)/4;
  926.         ptr->yorg =  ReadValue(21,7)/4;
  927.         ptr->zorg = -ReadValue(30,7)/4;
  928.         ProcessAtom( ptr );
  929.     }
  930.  
  931.     for( i=0; i<bonds; i++ )
  932.     {   FetchRecord();
  933.         sscanf(Record,"%d %d %d",&serno,&srcatm,&dstatm);
  934.  
  935.         chptr = Record;
  936.         while( *chptr && !isalpha(*chptr) )
  937.             chptr++;
  938.  
  939.         if( *chptr =='A' )             /* AROMATIC */
  940.         {   CreateBond(srcatm,dstatm,AromBondFlag);
  941.         } else if( *chptr == 'D' )     /* DOUBLE */
  942.         {   CreateBond(srcatm,dstatm,DoubBondFlag);
  943.         } else if( *chptr == 'T' )     /* TRIPLE */
  944.         {   CreateBond(srcatm,dstatm,TripBondFlag);
  945.         } else if( *chptr == 'H' )     /* HYDROGEN */
  946.         {   CreateBond(srcatm,dstatm,HydrBondFlag);
  947.         } else /* (*chptr == 'S') */   /* SINGLE */
  948.             CreateBond(srcatm,dstatm,NormBondFlag);
  949.     }
  950.     return( True );
  951. }
  952.  
  953.  
  954. int LoadCharmmMolecule( fp )
  955.     FILE *fp;
  956. {
  957.     auto char buffer[4];
  958.     register Atom __far *ptr;
  959.     register int resno,serno;
  960.     register int init,chain;
  961.     register int atoms,i;
  962.  
  963.     DataFile = fp;
  964.  
  965.     do {
  966.         FetchRecord();
  967.     } while( *Record=='*' );
  968.     atoms = (int)ReadValue(0,5);
  969.     if( !atoms ) return False;
  970.  
  971.     MinHetaRes = MaxHetaRes = 0;
  972.     strcpy(InfoFileName,DataFileName);
  973.     MainGroupCount = 0;
  974.  
  975.     chain = 0;
  976.     init = False;
  977.     CurChain = NULL;
  978.     for( serno=0; serno<atoms; serno++ )
  979.     {   FetchRecord();
  980.  
  981.         if( !CurChain || strncmp(Record+51,buffer,4) )
  982.         {   for( i=0; i<4; i++ )
  983.                 buffer[i] = Record[51+i];
  984.             CreateChain(chain+49);
  985.             chain++;
  986.         }
  987.  
  988.         resno = (int)ReadValue(5,5);
  989.         if( !CurGroup || (CurGroup->serno!=resno) )
  990.         {   CreateGroup( GroupPool );
  991.             CurGroup->refno = FindResNo(Record+11);
  992.             CurGroup->serno = resno;
  993.             ProcessGroup( False );
  994.         }
  995.  
  996.         ptr = CreateAtom();
  997.         ptr->refno = ComplexAtomType(Record+15);
  998.         ptr->temp = (int)ReadValue(60,9);
  999.         ptr->serno = (int)ReadValue(0,5);
  1000.         /* ptr->serno = serno+1; */
  1001.  
  1002.         ptr->xorg =  ReadValue(20,8)/4;
  1003.         ptr->yorg =  ReadValue(30,8)/4;
  1004.         ptr->zorg = -ReadValue(40,8)/4;
  1005.         ProcessAtom( ptr );
  1006.     }
  1007.     return( True );
  1008. }
  1009.  
  1010.  
  1011. static int MOPACAtomType( type )
  1012.     char *type;
  1013. {
  1014.     auto char name[4];
  1015.     register char ch1,ch2;
  1016.     register int i;
  1017.  
  1018.     if( *type == ' ' )
  1019.         type++;
  1020.  
  1021.     name[2] = name[3] = ' ';
  1022.     if( isdigit(type[0]) )
  1023.     {   i = *type++ - '0';
  1024.         while( isdigit(*type) )
  1025.             i = (10*i) + (*type++ - '0');
  1026.  
  1027.         /* Last Atom in File! */
  1028.         if( i == 0 )
  1029.         {   return( -1 );
  1030.         } else if( i >= 99 )
  1031.             return( 1 );
  1032.  
  1033.         /* Construct Name */
  1034.         ch1 = Element[i].symbol[0];
  1035.         ch2 = Element[i].symbol[1];
  1036.         if( ch2 == ' ' )
  1037.         {   name[1] = ch1;
  1038.             name[0] = ' ';
  1039.         } else
  1040.         {   name[1] = ToUpper(ch2);
  1041.             name[0] = ch1;
  1042.         }
  1043.  
  1044.     } else
  1045.     {   ch1 = ToUpper(type[0]);
  1046.         ch2 = ToUpper(type[1]);
  1047.         if( (ch1=='X') || (ch1=='+') || (ch1=='-') )
  1048.         {   return( 1 );
  1049.         } else if( (ch1=='T') && (ch2=='V') )
  1050.             return( 1 );
  1051.  
  1052.         if( ch2 && (ch2!=' ') && (ch2!='(') && !isdigit(ch2) )
  1053.         {   name[0] = ch1;
  1054.             name[1] = ch2;
  1055.         } else
  1056.         {   name[1] = ch1;
  1057.             name[0] = ' ';
  1058.         }
  1059.     }
  1060.     return( NewAtomType(name) );
  1061. }
  1062.  
  1063.  
  1064. static int ReadMOPACOutputFile()
  1065. {
  1066.     register Atom __far *atm;
  1067.     register int i,init;
  1068.     register char *ptr;
  1069.  
  1070.     init = False;
  1071.     while( FetchRecord() )
  1072.     {   ptr = Record;
  1073.         while( *ptr == ' ' )
  1074.             ptr++;
  1075.  
  1076.         if( !strncmp(ptr,"CARTESIAN COORDINATES",21) )
  1077.         {   for( i=0; i<3; i++ )
  1078.                 FetchRecord();
  1079.  
  1080.             if( Database )
  1081.             {   atm = CurGroup->alist;
  1082.                 MMinMaxFlag = False;
  1083.                 HasHydrogen = False;
  1084.                 MainAtomCount = 0;
  1085.             }
  1086.  
  1087.             while( FetchRecord() && *Record && isdigit(Record[5]) )
  1088.             {   if( !Database )
  1089.                 {   atm = (Atom __far*)0;
  1090.                     CreateMolGroup();
  1091.                     init = True;
  1092.                 }
  1093.  
  1094.                 if( !atm )
  1095.                 {   atm = CreateAtom();
  1096.                     atm->serno = (int)ReadValue(0,6);
  1097.                     atm->refno = MOPACAtomType(Record+14);
  1098.                     atm->temp = 0;
  1099.  
  1100.                     atm->xorg = ReadValue(20,10)/40;
  1101.                     atm->yorg = ReadValue(30,10)/40;
  1102.                     atm->zorg = ReadValue(40,10)/40;
  1103.                 } else
  1104.                 {   atm->xorg = ReadValue(30,10)/40;
  1105.                     atm->yorg = ReadValue(40,10)/40;
  1106.                     atm->zorg = ReadValue(50,10)/40;
  1107.                 }
  1108.                 ProcessAtom(atm);
  1109.                 atm = atm->anext;
  1110.             }
  1111.              
  1112.         } else if( !strncmp(ptr,"NET ATOMIC CHARGES",18) )
  1113.         {   FetchRecord();
  1114.             FetchRecord();
  1115.  
  1116.             if( Database )
  1117.             {   atm = CurGroup->alist;
  1118.                 MMinMaxFlag = False;
  1119.                 HasHydrogen = False;
  1120.                 MainAtomCount = 0;
  1121.             }
  1122.  
  1123.             while( FetchRecord() && strncmp(Record," DIPOLE",7) )
  1124.             {   if( !Database )
  1125.                 {   atm = (Atom __far*)0;
  1126.                     CreateMolGroup();
  1127.                 }
  1128.  
  1129.                 if( !atm )
  1130.                 {   atm = CreateAtom();
  1131.                     atm->serno = (int)ReadValue(0,12);
  1132.                     atm->refno = MOPACAtomType(Record+21);
  1133.                     atm->temp = (int)(ReadValue(27,13)/100);
  1134.                     atm->xorg = atm->yorg = atm->zorg = 0;
  1135.                 } else
  1136.                     atm->temp = (int)(ReadValue(27,13)/100);
  1137.                 ProcessAtom(atm);
  1138.                 atm = atm->anext;
  1139.             }
  1140.         }
  1141.     }
  1142.  
  1143.     if( !init )
  1144.     {   if( Database )
  1145.             DestroyDatabase();
  1146.         return( False );
  1147.     } else return( True );
  1148. }
  1149.  
  1150.  
  1151. static int MoreMOPACKeywords()
  1152. {
  1153.     register char *ptr;
  1154.  
  1155.     ptr = Record;
  1156.     while( *ptr )
  1157.     {   if( *ptr == '+' )
  1158.             if( !ptr[1] || (ptr[1]==' ') )
  1159.                 return(True);
  1160.  
  1161.         /* Skip Next Keyword */
  1162.         while( *ptr && *ptr!=' ' ) ptr++;
  1163.         while( *ptr == ' ' ) ptr++;
  1164.     }
  1165.     return( False );
  1166. }
  1167.  
  1168.  
  1169. int LoadMOPACMolecule( fp )
  1170.     FILE *fp;
  1171. {
  1172.     static int na,nb,nc,lopt;
  1173.     static double dist,angle,dihed;
  1174.     register IntCoord __far *coord;
  1175.     register Atom __far *aptr;
  1176.     register int count,refno;
  1177.     register int cartflag;
  1178.     register char *ptr;
  1179.  
  1180.     DataFile = fp;
  1181.     FetchRecord();
  1182.  
  1183.     /* Test for MOPAC output file */
  1184.     if( !strncmp(Record," ***",4) )
  1185.         return( ReadMOPACOutputFile() );
  1186.  
  1187.     /* MOPAC Keywords */
  1188.     while( MoreMOPACKeywords() )
  1189.         FetchRecord();
  1190.  
  1191.     FetchRecord(); /* Molecule Name */
  1192.     ExtractString(78,Record,InfoMoleculeName);
  1193.     FetchRecord(); /* Comments */
  1194.  
  1195.     count = 0;
  1196.     cartflag = False;
  1197.     InitInternalCoords();
  1198.     while( FetchRecord() )
  1199.     {   /* Process Record! */
  1200.         for( ptr=Record; *ptr; ptr++ )
  1201.             if( (*ptr==',') || (*ptr==0x09) )
  1202.                 *ptr = ' ';
  1203.  
  1204.         ptr = Record;
  1205.         while( *ptr == ' ' )
  1206.            ptr++;
  1207.  
  1208.         if( !*ptr ) break;
  1209.         refno = MOPACAtomType(ptr);
  1210.         if( refno == -1 ) break;
  1211.  
  1212.         while( *ptr && (*ptr!=' ') )
  1213.             if( *ptr == '(' )
  1214.             {   /* Skip Atom Label */
  1215.                 while( *ptr && (*ptr!=')') )
  1216.                     ptr++;
  1217.             } else ptr++;
  1218.  
  1219.         na = nb = nc = 0;
  1220.         dist = angle = dihed = 0.0;
  1221.         sscanf(ptr,"%lf %*d %lf %*d %lf %d %d %d %d",
  1222.                &dist, &angle, &dihed, &lopt, &na, &nb, &nc );
  1223.         count++;
  1224.  
  1225.         if( count == 3 )
  1226.         {   /* Handle missing dihedral */
  1227.             if( lopt == 2 )
  1228.             {   na = 1;  nb = 2;
  1229.                 dihed = 0.0;
  1230.             } else if( lopt == 1)
  1231.             {   /* Safe FP comparison for Cartesian */
  1232.                 if( (dihed>=1.9999) && (dihed<=2.0001) )
  1233.                 {   na = 2;  nb = 1;
  1234.                     dihed = 0.0;
  1235.                 }
  1236.             }
  1237.         } else if( count == 4 )
  1238.             cartflag = (na == 0);
  1239.  
  1240.         coord = AllocInternalCoord();
  1241.         coord->na = na; coord->nb = nb; coord->nc = nc;
  1242.         coord->refno = refno;
  1243.         coord->angle = angle;
  1244.         coord->dihed = dihed;
  1245.         coord->dist = dist;
  1246.     }
  1247.  
  1248.     if( !count )
  1249.         return( False );
  1250.  
  1251.     /* Co-ordinate conversion! */
  1252.     if( !cartflag )
  1253.         if( !ConvertInternal2Cartesian() )
  1254.         {   FreeInternalCoords();
  1255.             if( CommandActive )
  1256.                 WriteChar('\n');
  1257.             WriteString("Error: Invalid MOPAC z-matrix file!\n\n");
  1258.             CommandActive=False;
  1259.             return( False );
  1260.         }
  1261.  
  1262.     count = 0;
  1263.     for( coord=IntList; coord; coord=coord->inext )
  1264.         if( coord->refno != 1 )
  1265.         {   if( !Database )
  1266.                 CreateMolGroup();
  1267.  
  1268.             aptr = CreateAtom();
  1269.             aptr->refno = (Byte)coord->refno;
  1270.             aptr->serno = ++count;
  1271.             aptr->temp = 0;
  1272.  
  1273.             aptr->xorg = (Long)(250.0*coord->dist);
  1274.             aptr->yorg = (Long)(250.0*coord->angle);
  1275.             aptr->zorg = (Long)(250.0*coord->dihed);
  1276.             ProcessAtom(aptr);
  1277.         } else count++;
  1278.  
  1279.     FreeInternalCoords();
  1280.     return( True );
  1281. }
  1282.  
  1283.  
  1284. int LoadMacroModelMolecule( fp )
  1285.     FILE *fp;
  1286. {
  1287. #ifdef MMIO
  1288.     return( True );
  1289. #else
  1290.     register char *src,*dst;
  1291.     register int i;
  1292.     auto int atoms;
  1293.  
  1294.     DataFile = fp;
  1295.  
  1296.     /* Number of Atoms & Description */
  1297.     FetchRecord();
  1298.     sscanf(Record,"%d",&atoms);
  1299.  
  1300.     src = Record;
  1301.     dst = InfoMoleculeName;
  1302.     for( i=0; i<78; i++ )
  1303.         if( *src ) *dst++ = *src++;
  1304.     *dst = '\0';
  1305.  
  1306.     for( i=0; i<atoms; i++ )
  1307.     {    FetchRecord();
  1308.     }
  1309.     return( True );
  1310. #endif
  1311. }
  1312.  
  1313.  
  1314. int LoadBiosymMolecule( fp )
  1315.     FILE *fp;
  1316. {
  1317.     return( True );
  1318. }
  1319.  
  1320.  
  1321. int LoadSHELXMolecule( fp )
  1322.     FILE *fp;
  1323. {
  1324.     return( True );
  1325. }
  1326.  
  1327.  
  1328. int LoadFDATMolecule( fp )
  1329.     FILE *fp;
  1330. {
  1331.     return( True );
  1332. }
  1333.  
  1334.  
  1335. /*=================================*/
  1336. /* Molecule File Format Generation */
  1337. /*=================================*/
  1338.  
  1339. int SavePDBMolecule( filename )
  1340.     char *filename;
  1341. {
  1342.     register double x, y, z;
  1343.     register Group __far *prev;
  1344.     register Chain __far *chain;
  1345.     register Group __far *group;
  1346.     register Atom __far *aptr;
  1347.     register char *ptr;
  1348.     register int count;
  1349.     register char ch;
  1350.     register int i;
  1351.  
  1352.     if( !Database )
  1353.         return( False );
  1354.  
  1355.     DataFile = fopen( filename, "w" );
  1356.     if( !DataFile )
  1357.     {   if( CommandActive )
  1358.             WriteChar('\n');
  1359.         WriteString("Error: Unable to create file!\n\n");
  1360.         CommandActive=False;
  1361.         return( False );
  1362.     }
  1363.  
  1364.     if( *InfoClassification || *InfoIdentCode )
  1365.     {   fputs("HEADER    ",DataFile);
  1366.  
  1367.         ptr = InfoClassification;
  1368.         for( i=11; i<=50; i++ )
  1369.             putc( (*ptr ? *ptr++ : ' '), DataFile );
  1370.         fprintf(DataFile,"13-JUL-93   %.4s\n",InfoIdentCode);
  1371.     }
  1372.  
  1373.     if( *InfoMoleculeName )
  1374.         fprintf(DataFile,"COMPND    %.60s\n",InfoMoleculeName);
  1375.  
  1376.     prev = (void __far*)0;
  1377.  
  1378.     count = 1;
  1379.     ForEachAtom
  1380.         if( aptr->flag&SelectFlag )
  1381.         {   if( prev && (chain->ident!=ch) )
  1382.                 fprintf( DataFile, "TER   %5d      %.3s %c%4d \n",
  1383.                          count++, Residue[prev->refno], ch, prev->serno);
  1384.  
  1385.             if( aptr->flag&HeteroFlag )
  1386.             {      fputs("HETATM",DataFile);
  1387.             } else fputs("ATOM  ",DataFile);
  1388.             fprintf( DataFile, "%5d %.4s %.3s %c%4d    ",
  1389.                      count++, ElemDesc[aptr->refno], Residue[group->refno],
  1390.                      chain->ident, group->serno );
  1391.  
  1392.             x = (double)aptr->xorg/250.0;
  1393.             y = (double)aptr->yorg/250.0;
  1394.             z = (double)aptr->zorg/250.0;
  1395.  
  1396. #ifdef INVERT
  1397.             fprintf(DataFile,"%8.3f%8.3f%8.3f",x,-y,-z);
  1398. #else
  1399.             fprintf(DataFile,"%8.3f%8.3f%8.3f",x,y,-z);
  1400. #endif
  1401.             fprintf(DataFile,"  1.00%6.2f\n",aptr->temp/100.0);
  1402.  
  1403.             ch = chain->ident;
  1404.             prev = group;
  1405.         }
  1406.  
  1407.     if( prev )
  1408.         fprintf( DataFile, "TER   %5d      %.3s %c%4d \n",
  1409.                  count, Residue[prev->refno], ch, prev->serno);
  1410.  
  1411.     fputs("END   \n",DataFile);
  1412.     fclose( DataFile );
  1413. #ifdef APPLEMAC
  1414.     SetFileInfo(filename,'RSML','TEXT',131);
  1415. #endif
  1416.     return( True );
  1417. }
  1418.  
  1419.  
  1420. int SaveMDLMolecule( filename )
  1421.     char *filename;
  1422. {
  1423.     register Chain __far *chain;
  1424.     register Group __far *group;
  1425.     register Atom __far *aptr;
  1426.     register Bond __far *bptr;
  1427.     register int atoms,bonds;
  1428.     register double x,y,z;
  1429.     register int ch,temp;
  1430.     register int atomno;
  1431.  
  1432. #ifndef APPLEMAC
  1433.     register struct tm *ptr;
  1434.     static time_t curtime;
  1435. #endif
  1436.  
  1437.     if( !Database )
  1438.         return( False );
  1439.  
  1440.     DataFile = fopen( filename, "w" );
  1441.     if( !DataFile )
  1442.     {   if( CommandActive )
  1443.             WriteChar('\n');
  1444.         WriteString("Error: Unable to create file!\n\n");
  1445.         CommandActive=False;
  1446.         return( False );
  1447.     }
  1448.  
  1449.     /* Write Mol file header */
  1450.     fprintf(DataFile,"%.80s\n  RasMol  ",InfoMoleculeName);
  1451.  
  1452. #ifndef APPLEMAC
  1453.     curtime = time((time_t*)0);
  1454.     ptr = localtime(&curtime);
  1455.     fprintf(DataFile,"%02d%02d%02d%02d%02d",ptr->tm_mon+1,ptr->tm_mday,
  1456.                              ptr->tm_year%100,ptr->tm_hour,ptr->tm_min);
  1457. #else
  1458.     fputs("0101951200",DataFile);
  1459. #endif
  1460.  
  1461.     atoms = 0;
  1462.     ForEachAtom
  1463.         if( aptr->flag & SelectFlag )
  1464.             atoms++;
  1465.  
  1466.     bonds = 0;
  1467.     ForEachBond
  1468.         if( bptr->srcatom->flag & bptr->dstatom->flag & SelectFlag )
  1469.              bonds++;
  1470.  
  1471.     fprintf(DataFile,"%cD\n\n", (MinZ||MaxZ)?'3':'2' );
  1472.     fprintf(DataFile,"%3d%3d",atoms,bonds);
  1473.     fputs("  0        0              1 V2000\n",DataFile);
  1474.  
  1475.     atomno = 1;
  1476.     ForEachAtom
  1477.         if( aptr->flag & SelectFlag )
  1478.         {   x = (double)aptr->xorg/250.0;
  1479.             y = (double)aptr->yorg/250.0;
  1480.             z = (double)aptr->zorg/250.0;
  1481. #ifdef INVERT
  1482.             fprintf(DataFile,"%10.4lf%10.4lf%10.4lf ",x,-y,-z);
  1483. #else
  1484.             fprintf(DataFile,"%10.4lf%10.4lf%10.4lf ",x,y,-z);
  1485. #endif
  1486.             fputc(Element[aptr->elemno].symbol[0],DataFile);
  1487.             fputc(Element[aptr->elemno].symbol[1],DataFile);
  1488.             fputs("  0  ",DataFile);
  1489.  
  1490.             ch = '0';
  1491.             /* Test for charges or b-factors */
  1492.             if( (MinMainTemp<0) || (MinHetaTemp<0) )
  1493.             {   temp = aptr->temp;
  1494.                 if( temp > 50 )
  1495.                 {   if( temp > 250 )
  1496.                     {   ch = '1';
  1497.                     } else if( temp > 150 )
  1498.                     {   ch = '2';
  1499.                     } else ch = '3';
  1500.                 } else if( temp < -50 )
  1501.                 {   if( temp < -250 )
  1502.                     {   ch = '7';
  1503.                     } else if( temp < -150 )
  1504.                     {   ch = '6';
  1505.                     } else ch = 5;
  1506.                 }
  1507.             } 
  1508.             fputc(ch,DataFile);
  1509.  
  1510.             fputs("  0  0  0  0  0  0  0  0  0  0\n",DataFile);
  1511.             aptr->mbox = atomno++;
  1512.         }
  1513.  
  1514.     ForEachBond
  1515.         if( bptr->srcatom->flag & bptr->dstatom->flag & SelectFlag )
  1516.         {   fprintf(DataFile,"%3d%3d  ",bptr->srcatom->mbox,
  1517.                                         bptr->dstatom->mbox);
  1518.             if( bptr->flag & AromBondFlag )
  1519.             {      fputc('4',DataFile);
  1520.             } else if( bptr->flag & TripBondFlag )
  1521.             {      fputc('3',DataFile);
  1522.             } else if( bptr->flag & DoubBondFlag )
  1523.             {      fputc('2',DataFile);
  1524.             } else fputc('1',DataFile);
  1525.             fputs("  0\n",DataFile);
  1526.         }
  1527.  
  1528.     fputs("M  END\n",DataFile);
  1529.     fclose( DataFile );
  1530. #ifdef APPLEMAC
  1531.     SetFileInfo(filename,'RSML','mMOL',131);
  1532. #endif
  1533.     return( True );
  1534. }
  1535.  
  1536.  
  1537. int SaveAlchemyMolecule( filename )
  1538.     char *filename;
  1539. {
  1540.     register Real x, y, z;
  1541.     register float xpos, ypos, zpos;
  1542.     register Chain __far *chain;
  1543.     register Group __far *group;
  1544.     register Atom __far *aptr;
  1545.     register Bond __far *bptr;
  1546.     register char *ptr;
  1547.     register int atomno;
  1548.     register int bondno;
  1549.     register int num;
  1550.  
  1551.     if( !Database )
  1552.         return( False );
  1553.  
  1554.     DataFile = fopen( filename, "w" );
  1555.     if( !DataFile )
  1556.     {   if( CommandActive )
  1557.             WriteChar('\n');
  1558.         WriteString("Error: Unable to create file!\n\n");
  1559.         CommandActive=False;
  1560.         return( False );
  1561.     }
  1562.  
  1563.     atomno = 0;
  1564.     ForEachAtom
  1565.         if( aptr->flag & SelectFlag )
  1566.             aptr->mbox = 0;
  1567.  
  1568.     ForEachBond
  1569.         if( ((bptr->srcatom->flag&bptr->dstatom->flag)&SelectFlag) &&
  1570.            !((bptr->srcatom->flag|bptr->dstatom->flag)&HydrogenFlag) )
  1571.         {   if( bptr->flag&AromBondFlag )
  1572.             {   bptr->srcatom->mbox = -1;
  1573.                 bptr->dstatom->mbox = -1;
  1574.             } else
  1575.             {   num = (bptr->flag&DoubBondFlag)? 2 : 1;
  1576.                 if( bptr->srcatom->mbox>0 )
  1577.                     bptr->srcatom->mbox += num;
  1578.                 if( bptr->dstatom->mbox>0 )
  1579.                     bptr->dstatom->mbox += num;
  1580.             }
  1581.         }
  1582.  
  1583.     fprintf(DataFile,"%5d ATOMS, ",MainAtomCount+HetaAtomCount);
  1584.     fprintf(DataFile,"%5d BONDS, ",InfoBondCount);
  1585.     fprintf(DataFile,"    0 CHARGES, %s\n", InfoMoleculeName );
  1586.  
  1587.     atomno = 1;
  1588.     ForEachAtom
  1589.         if( aptr->flag & SelectFlag )
  1590.         {   aptr->mbox = atomno;
  1591.             fprintf(DataFile,"%5d ",atomno++);
  1592.  
  1593.             switch( aptr->elemno )
  1594.             {   case( 6 ):  if( aptr->mbox == -1 )
  1595.                             {   ptr = "CAR ";
  1596.                             } else if( aptr->mbox == 1 )
  1597.                             {   ptr = "C3  ";
  1598.                             } else ptr = "C2  ";
  1599.                             fputs( ptr, DataFile );
  1600.                             break;
  1601.  
  1602.                 case( 7 ):  if( aptr->mbox == -1 )
  1603.                             {   ptr = "NAR ";
  1604.                             } else ptr = "N2  ";
  1605.                             fputs( ptr, DataFile );
  1606.                             break;
  1607.  
  1608.                 case( 8 ):  if( aptr->mbox == 2 )
  1609.                             {   ptr = "O2  ";
  1610.                             } else ptr = "O3  ";
  1611.                             fputs( ptr, DataFile );
  1612.                             break;
  1613.  
  1614.                 case( 1 ):  fputs( "H   ", DataFile );  break;
  1615.  
  1616.                 default:    ptr = ElemDesc[aptr->refno];
  1617.                             if( *ptr==' ' )
  1618.                             {   fprintf(DataFile,"%.3s ",ptr+1);
  1619.                             } else fprintf(DataFile,"%.4s",ptr);
  1620.             }
  1621.  
  1622.             x = aptr->xorg/250.0;
  1623.             y = aptr->yorg/250.0;
  1624.             z = aptr->zorg/250.0;
  1625.  
  1626.             /* Apply Current Viewpoint Rotation Matrix */
  1627.             xpos = (float)(x*RotX[0] + y*RotX[1] + z*RotX[2]);
  1628.             ypos = (float)(x*RotY[0] + y*RotY[1] + z*RotY[2]);
  1629.             zpos = (float)(x*RotZ[0] + y*RotZ[1] + z*RotZ[2]);
  1630.  
  1631. #ifdef INVERT
  1632.             fprintf(DataFile,"  %8.4f %8.4f %8.4f",xpos,-ypos,-zpos);
  1633. #else
  1634.             fprintf(DataFile,"  %8.4f %8.4f %8.4f",xpos,ypos,-zpos);
  1635. #endif
  1636.             fprintf(DataFile,"    %7.4f\n",aptr->temp/1000.0);
  1637.         }
  1638.  
  1639.     bondno = 1;
  1640.     ForEachBond
  1641.         if( (bptr->srcatom->flag&bptr->dstatom->flag) & SelectFlag )
  1642.         {   fprintf(DataFile,"%5d %5d %5d  ", bondno++,
  1643.                         bptr->srcatom->mbox, bptr->dstatom->mbox );
  1644.             if( bptr->flag & AromBondFlag )
  1645.             {   ptr = "AROMATIC\n";
  1646.             } else if( bptr->flag & TripBondFlag )
  1647.             {   ptr = "TRIPLE\n";
  1648.             } else if( bptr->flag & DoubBondFlag )
  1649.             {   ptr = "DOUBLE\n";
  1650.             } else ptr = "SINGLE\n";
  1651.             fputs( ptr, DataFile );
  1652.         }
  1653.  
  1654.     ForEachAtom
  1655.             if( aptr->flag & SelectFlag )
  1656.                 aptr->mbox = 0;
  1657.     fclose( DataFile );
  1658. #ifdef APPLEMAC
  1659.     SetFileInfo(filename,'RSML','TEXT',131);
  1660. #endif
  1661.     return( True );
  1662. }
  1663.  
  1664.  
  1665. int SaveXYZMolecule( filename )
  1666.     char *filename;
  1667. {
  1668.     if( !Database )
  1669.         return( False );
  1670.     return( True );
  1671. }
  1672.  
  1673.  
  1674. int SaveCIFMolecule( filename )
  1675.     char *filename;
  1676. {
  1677.     if( !Database )
  1678.         return( False );
  1679.     return( True );
  1680. }
  1681.  
  1682.